package gsw.tool.common;

import java.math.BigDecimal;
import java.nio.ByteBuffer;

import gsw.tool.datastructure.table.Stack;

/**
 * 数学运算
 */
public class ToolMath {
    //分隔符
    public static char star = ' ';

    /**
     * byte数组转int
     */
    public static int bytesToInt(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return 0;
        }
        return bytes[3] & 0xFF |
                (bytes[2] & 0xFF) << 8 |
                (bytes[1] & 0xFF) << 16 |
                (bytes[0] & 0xFF) << 24;
    }

    /**
     * int转byte数组
     */
    public static byte[] intToBytes(int a) {
        return new byte[]{
                (byte) ((a >> 24) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) (a & 0xFF)
        };
    }

    /**
     * long转byte数组
     */
    public static byte[] longToBytes(long x) {
        ByteBuffer buffer = ByteBuffer.allocate(8);
        buffer.putLong(0, x);
        return buffer.array();
    }

    /**
     * byte数组转long
     */
    public static long bytesToLong(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return 0;
        }
        ByteBuffer buffer = ByteBuffer.allocate(8);
        buffer.put(bytes, 0, bytes.length);
        buffer.flip();
        return buffer.getLong();
    }

    /**
     * 字节转16进制字符串
     */
    public static String byteToHexString(byte b) {
        char[] digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        char[] ob = new char[2];
        ob[0] = digit[b >>> 4 & 0x0F];
        ob[1] = digit[b & 0x0F];
        return new String(ob);
    }

    /**
     * byte[]转16进制字符串
     *
     * @param bytes
     * @return
     */
    public static String bytesToHexString(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(byteToHexString(b));
        }
        return sb.toString();
    }

    /**
     * 将16进制字符串转换为byte[]
     *
     * @param str
     * @return
     */
    public static byte[] hexStringToBytes(String str) {
        if (str == null || str.trim().equals("")) {
            return new byte[0];
        }

        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }


    /**
     * string转字符串
     */
    public static String stringToBitString(String s) {
        if (Tool.isEmpty(s)) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        for (char c : s.toCharArray()) {
            String str = Integer.toBinaryString(c);
            //str的位数小于8，就在它前面补0
            int length = 8 - str.length();
            for (int i = 0; i < length; i++) {
                sb.append('0');
            }
            sb.append(str);
        }
        return sb.toString();
    }


    /**
     * 将中缀表达式转化为后缀表达式，提升计算速度
     * 出入栈规则：
     * 1.如果是数字，直接取出
     * 2.如果栈顶为空，直接入栈
     * 3.如果是加减乘除，则与栈顶比较，优先级高于栈顶，直接入栈；优先级低于栈顶，先把栈顶出栈，然后与新的栈顶比较；直到优先级高于栈顶，然后入栈；
     * 4.如果是'('，直接入栈；
     * 5.如果是')'，则与栈顶比较，优先级高于栈顶，直接入栈；优先级低于栈顶，先把栈顶出栈，然后与新的栈顶比较;直到栈顶为'(',把'('出栈；
     *
     * @param expStr 中缀表达式
     * @return 后缀表达式
     */
    public static String getSuffixExpression(String expStr) {
        //添加结束符号')'
        char[] expChars = (expStr + Type.RSP.name).toCharArray();
        Stack<Character> stack = new Stack<Character>();
        StringBuffer stringBuffer = new StringBuffer();
        for (char c : expChars) {
            //如果是运算符
            if (Type.isSymbol(c)) {
                Character top = stack.get();
                if (top == null) {
                    stack.add(c);
                } else if (c == Type.LSP.name) {
                    stack.add(c);
                    //如果优先级低于栈顶
                } else if (Type.compareTo(top, c) >= 0) {
                    while (Type.compareTo(top, c) >= 0) {
                        //添加分隔符
                        stringBuffer.append(star);
                        //取出栈顶元素
                        stringBuffer.append(stack.pop());
                        top = stack.get();
                        if (top == null) {
                            break;
                        }
                        //如果插入的时')'，则遇到'('就一起出栈
                        if (top.charValue() == Type.LSP.name && c == Type.RSP.name) {
                            stack.pop();
                            break;
                        }
                    }
                    if (c != Type.RSP.name) {
                        stack.add(c);
                    }
                } else {
                    stack.add(c);
                }
                //添加分隔符
                if (c != Type.LSP.name && c != Type.RSP.name) {
                    stringBuffer.append(star);
                }
            } else {
                stringBuffer.append(c);
            }
        }
        return stringBuffer.toString();
    }

    /**
     * 计算后缀表达式
     *
     * @param expStr 后缀表达式
     * @return 计算结果
     */
    public static long countSuffixExpression(String expStr) {
        long result = 0;
        if (Tool.isEmpty(expStr)) {
            return result;
        }
        String[] array = expStr.split(Character.toString(star));
        Stack<String> stack = new Stack<String>();
        for (String s : array) {
            char c = s.charAt(0);
            //如果是运算符就计算
            if (Type.isSymbol(c)) {
                String a = stack.pop();
                String b = stack.pop();
                if (!Tool.isEmpty(a) && !Tool.isEmpty(b)) {
                    //先取出来的数放到运算符后面
                    BigDecimal bigA = new BigDecimal(b);
                    BigDecimal bigB = new BigDecimal(a);
                    BigDecimal bigC = null;
                    //做加法运算
                    if (c == Type.ADD.name) {
                        bigC = bigA.add(bigB);
                        //做减法运算
                    } else if (c == Type.MIN.name) {
                        bigC = bigA.subtract(bigB);
                        //做乘法运算
                    } else if (c == Type.MUL.name) {
                        bigC = bigA.multiply(bigB);
                        //做除法运算
                    } else if (c == Type.DIV.name) {
                        bigC = bigA.divide(bigB, 0, BigDecimal.ROUND_UP);
                    }
                    //运算结果入栈
                    stack.add(bigC.toString());
                }
                //如果是字符串，就入栈
            } else {
                stack.add(s);
            }
        }
        result = new BigDecimal(stack.get()).longValue();
        return result;
    }

    /**
     * 运算符号
     */
    public static enum Type {
        ADD('+', 1), MIN('-', 1), MUL('*', 2), DIV('/', 2), LSP('(', 0), RSP(')', 0);
        //运算符名称
        public char name;
        //运算符优先级
        public int index;

        Type(char name, int index) {
            this.name = name;
            this.index = index;
        }

        /**
         * 获取运算符号的优先级
         *
         * @param c
         * @return
         */
        public static int getID(char c) {
            for (Type type : values()) {
                if (type.name == c) {
                    return type.index;
                }
            }
            return -1;
        }

        /**
         * 判断是不是运算符号
         *
         * @param c 字符
         * @return
         */
        public static boolean isSymbol(char c) {
            for (Type type : values()) {
                if (type.name == c) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 比较优先级
         *
         * @param a
         * @param b
         * @return
         */
        public static int compareTo(char a, char b) {
            return getID(a) - getID(b);
        }
    }


}

